/// 生命周期参数
/// 根据借用规则一， 借用的生命周期不能长于出借方的生命周期
/// 标注生命周期参数并不能改变任何引用的生命周期长短，它只用于编译器的借用检查，来防止悬垂指针。
/// 生命周期参数是为了帮助借用检查器验证非法借用，
/// 函数间传入和返回的借用必须相关联，并且返回的借用生命周期必须比出借方的生命周期长
pub fn start() {
    let str = return_static_str();
    println!("{}", str);
    test_leak();
    test_leak();
}

fn test_leak() {
    let str: &'static str = return_static_str();
    println!("{:p}", str);
}

/// 函数签名中的生命周期参数
/// 函数名后面的<'a>为生命周期参数的声明，与泛型参数类似，必须先声明才能使用 。
/// 函数或方法参数的生命周期叫作输入生命周期 (input lifetime)，
/// 而返回值的生命周期被称为输 出生命周期(output lifetime)。
/// 函数签名的生命周期参数有这样的限制条件:输出(借用方)的生命周期长度必须不长
/// 于输入(出借方)的生命周期长度(此条件依然遵循借用规则一)
fn foo<'a>(s: &'a str, t: &'a str) -> &'a str {
    if s.len() > t.len() {
        s
    } else {
        t
    }
}

/// 禁止在没有任何输入参数的情况下返回引用
/// 从函数中返回 (输出) 一个引用，其生命周期参数必须与函数的参数 (输入) 相匹配，
/// 否则，标注生命周期参数也毫无意义
fn return_str<'a>() -> &'a str {
    let mut s = "Rust".to_string();
    for i in 0..3 {
        s.push_str("Good ");
    }
    // 返回&s[..]报错： returns a value referencing data owned by the current function
    &s[..];
    "这种返回是可以的，因为该字符串是' static 的"
}

/// 使用不当会发生内存泄露
fn return_static_str() -> &'static str {
    let temp = String::from("test");
    Box::leak(Box::new(temp))
}

fn th_longest<'a, 'b: 'a>(s: &'a str, t: &'b str) -> &'a str {
    if s.len() > t.len() {
        s
    } else {
        t
    }
}
